package com;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Vector;

import org.apache.xmlrpc.WebServer;

import de.dfki.util.xmlrpc.XmlRpc;
import de.dfki.util.xmlrpc.XmlRpc.Type;
import de.dfki.util.xmlrpc.client.XmlRpcClient;
import de.dfki.util.xmlrpc.server.XmlRpcHandlerFactory;

public class Peer {

	private static Peer peer = null;
	public PeerData localPeerData;
	public ArrayList<PeerData> peerList;
	private WebServer webserver;
	private XmlRpcClient client;

	/**
	 * Command line execution optional. Class can be separated.
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		Peer peer1 = new Peer("P1", "localhost", 6661, 10);
		Peer peer2 = new Peer("P2", "localhost", 6662, 10);
		Peer peer3 = new Peer("P3", "localhost", 6663, 10);
		Peer peer4 = new Peer("P4", "localhost", 6664, 10);
		Peer peer5 = new Peer("P5", "localhost", 6665, 10);
		peer1.startServer();
		peer2.startServer();
		peer3.startServer();
		peer4.startServer();
		peer5.startServer();
		peer3.ping("localhost", 6664, 0);
		peer3.ping("localhost", 6665, 0);
		peer5.ping("localhost", 6662, 0);
		peer3.printpList();

		peer1.commandLoop();
		// peer.ping("localhost", 6666, -1); // SelfTest ping
	}

	public Peer(String name, String address, int port, int capacity) {
		Vector<String> lpd = new Vector<String>();
		lpd.add(name);
		lpd.add(address);
		lpd.add("" + port);
		lpd.add("" + capacity);

		localPeerData = new PeerData(lpd);
		peerList = new ArrayList<PeerData>();
	}

	public void startServer() {
		try {

			System.out.println("Attempting to start XML-RPC Server...");
			webserver = new WebServer(localPeerData.port);
			webserver.addHandler("Peer",
					XmlRpcHandlerFactory.createHandlerFor(new RPC(this)));
			webserver.start();

			System.out.println("Started successfully.");
			System.out.println("Accepting requests.");
		} catch (Exception exception) {
			System.out.println(exception.getMessage());
			System.err.println("Server: " + exception);
		}
	}

	public void ping(String address, int port, int queryId) {
		ArrayList<PeerData> result = null;
		try {
			RPCApi remote_api = XmlRpc.createClient(RPCApi.class, "Peer",
					address, port);
			result = remote_api.query(queryId);

			// Add results
			for (PeerData p : result) {
				if (!peerList.contains(p) && !p.equals(localPeerData)
						&& peerList.size() < localPeerData.capacity) {
					System.out.println(localPeerData.name + ": Found peer:"
							+ p.name);
					peerList.add(p);
				}
			}

		} catch (Exception exception) {
			System.err.println("Client: " + exception);
			System.out.println("");
		}
	}

	public void printpList() {
		System.out.println(localPeerData.name + ": Peerlist:");
		for (PeerData p : peerList) {
			System.out.println("Name: " + p.name + ", Address: " + p.address
					+ ", Port: " + p.port);
		}
	}

	/**
	 * Initiate commandloop to call internal functions.
	 */
	private void commandLoop() {
		String command = "";
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				System.in));

		while (command != "exit") {
			System.out.print(localPeerData.name + ": ");

			try {
				command = reader.readLine();

			} catch (IOException e) {
				System.out.println("Could not read input: " + e.getMessage());
				e.printStackTrace();
			}

			switch (command.split(" ")[0]) {
			case "hello":
				System.out.println(localPeerData.name + ": Trying to query: "
						+ command.split(" ")[1] + " at port "
						+ command.split(" ")[2] + "...");
				ping(command.split(" ")[1],
						Integer.parseInt(command.split(" ")[2]), 0);
				break;
			case "name":
				String newname = command.split(" ")[1];
				localPeerData.name = newname;
				System.out.println("Changed name to: " + newname);
				break;
			case "plist":
				printpList();
				break;
			case "exit":
				webserver.shutdown();
				System.out.println(localPeerData.name + ": Exiting...");
				return;
			default:
				System.out.println("Unrecognized command, please try again");
				break;
			}
		}
	}
}
